﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using DynamicLoader;
using DynamicLoader.DataStructures;
using System.Threading;
using System.Collections.Generic;
using System.Linq;
namespace SSCCMembershipContent
{
	public static class DependancySizes
	{
		public static XAPName[] GetDependancies(XAPName XAP)
		{
			if (!DependancyRelationship.Any((X) => X.Key == XAP))
			{
				return new XAPName[0];
			}
			else
			{
				return DependancyRelationship.First((X) => X.Key == XAP).Value;
			}
		}
		static Dictionary<XAPName, XAPName[]> DependancyRelationship = new Dictionary<XAPName, XAPName[]>() 
		{ 
			{ "A_ManageUsers.xap", new XAPName[] { "System.Windows.Controls.xap" } }, 
			{ "A_DirectDBAccess.xap", new XAPName[] { "System.Windows.Controls.xap", "System.Windows.Data.xap", "BindableDataGrid.xap" } } 
		};
	}
	public class NavigateCommand : ICommand
	{
		#region Initialiser & Check for Editing
		static NavigateCommand()
		{
			DataModel.ChangeTracking.PendingChangesChanged += new EventHandler(ChangeTracking_PendingChangesChanged);
		}

		static void ChangeTracking_PendingChangesChanged(object sender, EventArgs e)
		{
			OnCanExecuteChanged();
		}
		#endregion
		
		#region Reference to the Main Page
		private static MainPage MP;
		public static MainPage MainPageInstance
		{
			get { return MP; }
			set
			{
				MP = value;
				OnCanExecuteChanged();
				MP.ContentLoader.ContentLoaded += new EventHandler(ContentLoader_ContentLoaded);
				MP.ContentOpening.Completed += new EventHandler(ContentOpening_Completed);
				MP.ContentClosing.Completed += new EventHandler(ContentClosing_Completed);
			}
		}
		#endregion

		static void ContentClosing_Completed(object sender, EventArgs e)
		{
			VisualStatus = VisualStatuses.In;
			//Begin Loading content
			MP.ContentLoader.UpdateContent(XAPName, 0, XAPName, ClassName, DependancySizes.GetDependancies(XAPName));
			//Force if it takes longer than 2 seconds - this displays progress bar.
			Timer T = new Timer(ForceOpenEarly, SynchronizationContext.Current, 2000, Timeout.Infinite);
		}

		static void ContentOpening_Completed(object sender, EventArgs e)
		{
			VisualStatus = VisualStatuses.Out;
		}
		private static NavigateDestination LastNav = "U_UserHome.UserHomePage";
		public static NavigateDestination LastNavigatedTo
		{
			get { return LastNav; }
			set
			{
				LastNav = value;
				OnCanExecuteChanged();
			}
		}

		static void ContentLoader_ContentLoaded(object sender, EventArgs e)
		{
			NavigationState = NavigationStates.Navigated;
			if (VisualStatus == VisualStatuses.In)
			{
				VisualStatus = VisualStatuses.GoingOut;
				MP.ContentOpening.Begin();
			}
			if (LastNavigatedTo.PostLoadAction != null)
			{
				LastNavigatedTo.PostLoadAction(MP.ContentLoader.CurrentContent);
			}
			Cache.Start();
		}
		static void ForceOpenEarly(object SC)
		{
			((SynchronizationContext)SC).Send((o) =>
				{
					if (VisualStatus == VisualStatuses.In)
					{
						VisualStatus = VisualStatuses.GoingOut;
						MP.ContentOpening.Begin();
					}
				}, null);
		}
		static string XAPName;
		static string ClassName;


		private static VisualStatuses _VisualStatus = VisualStatuses.Out;
		private static VisualStatuses VisualStatus { get { return _VisualStatus; } set { _VisualStatus = value; OnCanExecuteChanged(); } }
		private static NavigationStates _NavigationState = NavigationStates.Navigated;
		private static NavigationStates NavigationState { get { return _NavigationState; } set { _NavigationState = value; OnCanExecuteChanged(); } }
		private enum VisualStatuses
		{
			Out,
			GoingIn,
			In,
			GoingOut
		}
		private enum NavigationStates
		{
			Navigating,
			Navigated
		}

		static Dictionary<EventHandler, object> _CanExecuteChanged = new Dictionary<EventHandler, object>();
		static void OnCanExecuteChanged()
		{
			foreach (var item in _CanExecuteChanged)
			{
				//The sender is always the expected class as if it wasn't static.
				item.Key(item.Value, EventArgs.Empty);
			}
		}

		#region ICommand Members


		public bool CanExecute(object parameter)
		{
			if (parameter != null)
			{
				NavigateDestination ND;
				if (parameter is NavigateDestination)
				{
					ND = (NavigateDestination)parameter;
				}
				else if (parameter is string)
				{
					ND = (string)parameter;
				}
				else
				{
					return false;
				}
				return (MainPageInstance != null)  //We have a reference to the main page
					&& ND != LastNavigatedTo //We aren't navigating to the page we're already on
					&& (NavigationState == NavigationStates.Navigated) //We aren't in the process of navigating
					&& (VisualStatus == VisualStatuses.Out) //We aren't in the process of animating the page
					&& !DataModel.ChangeTracking.IsChanged; //We don't have unsaved changes pending
			}
			return false;

		}

		public event EventHandler CanExecuteChanged
		{
			add
			{
				if (_CanExecuteChanged.ContainsKey(value)) _CanExecuteChanged.Remove(value);
				_CanExecuteChanged.Add(value, this);
			}
			remove { _CanExecuteChanged.Remove(value); }
		}


		public void Execute(object parameter)
		{
			NavigateDestination NavDest;
			if (parameter is NavigateDestination)
			{
				NavDest = (NavigateDestination)parameter;
			}
			else if (parameter is string)
			{
				NavDest = (string)parameter;
			}
			else
			{
				return;
			}

			NavigateTo(NavDest);
		}
		public static void NavigateTo(NavigateDestination Destination)
		{
			Cache.Stop();
			NavigationState = NavigationStates.Navigating;
			VisualStatus = VisualStatuses.GoingIn;

			LastNavigatedTo = Destination;

			XAPName = Destination.XAP;
			ClassName = Destination.Path;

			//Don't save in Isolated Storage
			XAPLoader XAPL = new XAPLoader(new SSCCMembership.ExternalDependanciesLoader(), XAPName, 0);
			XAPL.Start();

			MP.Animation2.Value = -(MP.ActualWidth + 20);
			MP.ContentClosing.Begin();
		}
		#endregion
	}
	public class NavigateDestination:DependencyObject, IEquatable<NavigateDestination>
	{
		private string _XAP = null;
		public virtual string XAP { get 
		{ 
			if(_XAP != null)
				return _XAP; 
			else
				return Path.Substring(0, Path.IndexOf("."));
		}
			set { _XAP = value; }
		}
		public virtual string Path { get; set; }
		public virtual Action<UIElement> PostLoadAction { get; set; }

		public static implicit operator NavigateDestination(string Path)
		{
			return new NavigateDestination() { Path = Path };
		}

		public override string ToString()
		{
			return Path.ToString();
		}

		public static bool operator ==(NavigateDestination ND1, NavigateDestination ND2)
		{
			if ((object)ND1 == null)
				return ((object)ND2) == null;
			return ND1.Equals(ND2);
		}
		public static bool operator !=(NavigateDestination ND1, NavigateDestination ND2)
		{
			return !(ND1 == ND2);
		}
		// override object.Equals
		public override bool Equals(object obj)
		{
			if (obj == null || GetType() != obj.GetType())
			{
				return false;
			}
			else
			{
				return this.Equals((NavigateDestination)obj);
			}
		}

		// override object.GetHashCode
		public override int GetHashCode()
		{
			return XAP.GetHashCode() + Path.GetHashCode() + PostLoadAction.GetHashCode();
		}

		#region IEquatable<NavigateDestination> Members

		public bool Equals(NavigateDestination other)
		{
			if((object)other == null)
				return false;
			return Path == other.Path & XAP == other.XAP & PostLoadAction == other.PostLoadAction;
		}

		#endregion
	}
}
